﻿#region License
/* ---------------------------------------------------------------- *
 *
 * This file is part of the Xcoordination Application Space
 * ("XcoAppSpace") http://www.xcoordination.com
 *
 * Copyright (C) 2009 Xcoordination http://www.xcoordination.com
 *
 * XcoAppSpace is free software; you can redistribute it and/or
 * modify it under the terms of version 2 of the GNU General
 * Public License as published by the Free Software Foundation.
 *
 * XcoAppSpace is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/
 * or write to the Free Software Foundation, Inc., 51 Franklin
 * Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 * ---------------------------------------------------------------- */
#endregion

using System;
using System.ServiceModel.Description;
using System.ServiceModel.Channels;
using System.ServiceModel;
using System.Text;
namespace XcoAppSpaces.Transport.WCF
{
    /// <summary>
    /// Helper for different WCF Bindings
    /// </summary>
    public class BindingsHelper:IBindingsHelper
    {
        /// <summary>
        /// Get the current binding scheme
        /// </summary>
        private Binding usedBindingScheme;
        private string netTcpAppSpace = "XcoAppSpace";

		/// <summary>
		/// Generates an Uri for NetTcp binding.
		/// </summary>
		/// <param name="port">The port for the uri.</param>
		/// <returns>The generated uri.</returns>
        public Uri GenerateStandardNetTcp(int port)
        {
            UriBuilder uriB = new UriBuilder();
            uriB.Scheme = Uri.UriSchemeNetTcp;
            uriB.Host = System.Environment.MachineName.ToLower();
            uriB.Port = port;
            uriB.Path = netTcpAppSpace;
            return uriB.Uri;
        }

		/// <summary>
		/// Converts an address to be correct for current binding.
		/// </summary>
		/// <param name="address">The address to be converted.</param>
		/// <returns>The converted address.</returns>
        public string Convert( string address)
        {
            return Convert(usedBindingScheme,address).ToString();
        }

		/// <summary>
		/// Converts the given address for the given binding type.
		/// </summary>
		/// <param name="bindingType">The binding type to be used.</param>
		/// <param name="address">The address to be converted.</param>
		/// <returns>The converted address.</returns>
        public Uri Convert(Binding bindingType, string address)
        {
            if (usedBindingScheme == null)
            {
                usedBindingScheme = bindingType;
            }
          
            if (bindingType is NetTcpBinding)
            {
                return Convert((NetTcpBinding)bindingType, address);
            }
            else if (bindingType is NetNamedPipeBinding)
            {
                return Convert((NetNamedPipeBinding)bindingType, address);                
            }
            else if (bindingType is WSHttpBinding)
            {
                return Convert((WSHttpBinding)bindingType, address);
            }
            return null;
        }

        /// <summary>
        /// Converts the given address for the NetNamedPipeBinding.
        /// </summary>
        /// <param name="bindingType">The NetNamedPipeBinding type-information.</param>
        /// <param name="address">The address to be converted.</param>
        /// <returns>The converted address.</returns>
        private Uri Convert(NetNamedPipeBinding bindingType, string address)
        {
            UriBuilder uriB = new UriBuilder();           
            uriB.Scheme = bindingType.Scheme;

            Uri tmp = null;
            try
            {//try to convert the address into uri
                tmp = new Uri(address);
            }
            catch { }

            if (tmp == null || tmp.Scheme == null)
            {//Create new path, when convert fails from standard uri-convert
                string[] parts = address.Split('/');
                if (parts.Length >= 2)
                {
                    uriB.Host = parts[0];
                    //create path without hostpart
                    uriB.Path = address.Substring(parts[0].Length + 1, address.Length - parts[0].Length - 1);
                }
                else
                {//only hostname known
                    uriB.Host = parts[0];
                }
            }
            else
            {
                if (uriB.Scheme == tmp.Scheme)
                {//well known scheme, return direct
                    return tmp;
                }
                uriB.Host = tmp.Host;
                uriB.Path = tmp.PathAndQuery;
            }
            return uriB.Uri;
        }

        /// <summary>
        /// Converts the given address for the NetTcpBinding.
        /// </summary>
        /// <param name="bindingType">The NetTcpBinding type-information.</param>
        /// <param name="address">The address to be converted.</param>
        /// <returns>The converted address.</returns>
        private Uri Convert(NetTcpBinding bindingType, string address)
        {
            UriBuilder uriB = new UriBuilder();
            uriB.Scheme = bindingType.Scheme;
            Uri tmp = null;
            try
            {//try to convert the address into uri
                tmp = new Uri(address);
            }
            catch { }
            if (tmp != null && uriB.Scheme == tmp.Scheme)
            {//well known scheme, return direct
                return tmp;
            }
            uriB.Path = "";
            string[] parts = address.Split(':');
            if (parts.Length >= 2)
            {//convert into host, port and path
                uriB.Host = parts[0];
                parts = parts[1].Split('/');
                uriB.Port = int.Parse(parts[0]);
                if (parts.Length > 1)
                {
                    uriB.Path = parts[1];
                }
            }
            else
            {//only hostname known
                uriB.Host = parts[0];
            }
            if (!string.IsNullOrEmpty(uriB.Path) && !uriB.Path.EndsWith("/"))
            {//check path end
                uriB.Path += "/";
            }
            uriB.Path += netTcpAppSpace;

            return uriB.Uri;
        }

        /// <summary>
        /// Converts the given address for the NetTcpBinding.
        /// </summary>
        /// <param name="bindingType">The WSHttpBinding type-information.</param>
        /// <param name="address">The address to be converted.</param>
        /// <returns>The converted address.</returns>
        private Uri Convert(WSHttpBinding bindingType, string address)
        {
            UriBuilder uriB = new UriBuilder();
            uriB.Scheme = bindingType.Scheme;
            Uri tmp = null;
            try
            {//try to convert the address into uri
                tmp = new Uri(address);
            }
            catch { }
            if (tmp != null && uriB.Scheme == tmp.Scheme)
            {//well known scheme, return direct
                return tmp;
            }
            uriB.Path = "";
            string[] parts = address.Split(':');
            if (parts.Length >= 2)
            {//convert into host, port and path
                uriB.Host = parts[0];
                parts = parts[1].Split('/');
                uriB.Port = int.Parse(parts[0]);
                if (parts.Length > 1)
                {
                    uriB.Path = parts[1];
                }
            }
            else
            {//only hostname known
                uriB.Host = parts[0];
            }
            if (!string.IsNullOrEmpty(uriB.Path) && !uriB.Path.EndsWith("/"))
            {//check path end
                uriB.Path += "/";
            }
            uriB.Path += netTcpAppSpace;

            return uriB.Uri;
        }

		/// <summary>
		/// Gets the address value that should be returned by the communication
		/// service's ServerAdress property (binding info is removed from the address).
		/// </summary>
		/// <param name="addr">The address.</param>
		/// <returns>The value for the ServerAddress property.</returns>
        public string ServerAddr(Uri addr)
        {
            if (usedBindingScheme is NetTcpBinding)
            {
                return addr.Host + ":" + addr.Port;
            }
            else if (usedBindingScheme is NetNamedPipeBinding)
            {
                StringBuilder str = new StringBuilder();
                str.Append(addr.Host);
                if (!addr.PathAndQuery.StartsWith("/"))
                    str.Append("/");
                str.Append(addr.PathAndQuery);
                return str.ToString();
            }
            return addr.ToString();
        }

		/// <summary>
		/// Extracts the port value from the given address.
		/// </summary>
		/// <param name="addr">The address.</param>
		/// <returns>The port value.</returns>
        public int Port(Uri addr)
        {
           
            if (usedBindingScheme == null ||usedBindingScheme is NetTcpBinding)
            {
                if (addr != null)
                {
                    return addr.Port;
                }
                else
                    return 0;
            }
           
            return -1;
        }
    }
}